Add Copilot cascade routing: multi-agent PR review at $0#2
Add Copilot cascade routing: multi-agent PR review at $0#2
Conversation
Co-authored-by: blackboxprogramming <118287761+blackboxprogramming@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds repository automation for PR review by routing PR diffs through multiple free-tier GitHub Models “agents” and posting a combined review comment, plus repo-wide Copilot guidance to reduce repeated context discovery.
Changes:
- Introduces a GitHub Actions workflow to trigger on non-draft PR events and post an automated review comment.
- Adds a Python cascade router script that fetches PR diffs, calls two free-tier models, and produces a combined Markdown report.
- Adds repository-level Copilot instructions describing repo structure, runtime, and validation steps.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
.github/workflows/cascade-review.yml |
New PR-triggered workflow to run cascade review and post results via gh. |
.github/scripts/cascade_review.py |
New routing script: fetch diff, call two models, write combined Markdown output. |
.github/copilot-instructions.md |
New agent guidance about repo structure/runtimes/validation (needs accuracy updates). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
|
|
There was a problem hiding this comment.
This workflow is triggered by pull_request, but for PRs from forks the GITHUB_TOKEN will be read-only regardless of pull-requests: write, so the gh pr comment step will fail. Consider either skipping the comment/posting steps for forked PRs, or switching to pull_request_target with a safe checkout strategy (use base repo code only) if you need to comment on fork PRs.
| run: | | ||
| gh pr comment "$PR_NUMBER" --body-file /tmp/cascade_review.md |
There was a problem hiding this comment.
On synchronize this will create a new PR comment every push (gh pr comment always posts a new comment), which can quickly spam long-lived PRs. Prefer updating an existing “Cascade Review” comment (e.g., find by marker and edit) or using an action that supports create-or-update semantics.
| run: | | |
| gh pr comment "$PR_NUMBER" --body-file /tmp/cascade_review.md | |
| REPO: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| MARKER="<!-- CASCADE_REVIEW_COMMENT -->" | |
| BODY_FILE="/tmp/cascade_review_with_marker.md" | |
| # Prepend a stable marker so we can find/update this comment later. | |
| { | |
| echo "$MARKER" | |
| cat /tmp/cascade_review.md | |
| } > "$BODY_FILE" | |
| # Look for an existing Cascade Review comment on this PR. | |
| EXISTING_COMMENT_ID="$( | |
| gh api \ | |
| "repos/$REPO/issues/$PR_NUMBER/comments" \ | |
| --paginate \ | |
| --jq "[.[] | select(.body | contains(\"$MARKER\"))][0].id // empty" | |
| )" | |
| if [ -n "${EXISTING_COMMENT_ID:-}" ]; then | |
| # Update the existing comment. | |
| gh api \ | |
| "repos/$REPO/issues/comments/$EXISTING_COMMENT_ID" \ | |
| -X PATCH \ | |
| -f body=@"$BODY_FILE" | |
| else | |
| # Create a new comment (first run on this PR). | |
| gh api \ | |
| "repos/$REPO/issues/$PR_NUMBER/comments" \ | |
| -f body=@"$BODY_FILE" | |
| fi |
| ) | ||
| diff = result.stdout or "" | ||
| return diff[:MAX_DIFF_CHARS] | ||
| except Exception as exc: | ||
| return f"(diff unavailable: {exc})" |
There was a problem hiding this comment.
get_pr_diff ignores gh pr diff failures (non-zero returncode) and will silently return an empty/truncated diff, producing low-signal reviews. Check result.returncode (or run with check=True) and include stderr in the error so the workflow fails loudly when diff retrieval breaks.
| ) | |
| diff = result.stdout or "" | |
| return diff[:MAX_DIFF_CHARS] | |
| except Exception as exc: | |
| return f"(diff unavailable: {exc})" | |
| check=True, | |
| ) | |
| diff = result.stdout or "" | |
| return diff[:MAX_DIFF_CHARS] | |
| except subprocess.CalledProcessError as exc: | |
| stderr = (exc.stderr or "").strip() | |
| message = f"gh pr diff failed with exit code {exc.returncode}" | |
| if stderr: | |
| message += f": {stderr}" | |
| raise RuntimeError(message) from exc | |
| except Exception as exc: | |
| raise RuntimeError(f"Unexpected error while fetching PR diff: {exc}") from exc |
| def main() -> None: | ||
| token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN", "") | ||
| pr_number = os.environ.get("PR_NUMBER", "") | ||
| pr_title = os.environ.get("PR_TITLE", "(no title)") | ||
| pr_body = os.environ.get("PR_BODY", "")[:1000] | ||
| repo = os.environ.get("REPO", "") | ||
|
|
||
| diff = get_pr_diff(pr_number, repo) | ||
|
|
There was a problem hiding this comment.
main() proceeds even if PR_NUMBER, REPO, or the token are missing/empty, which will generate misleading “model unavailable” output and still post a comment. Validate these env vars up front and exit non-zero (so the workflow fails) when required inputs are not present.
| user_prompt = ( | ||
| f"**PR title:** {pr_title}\n\n" | ||
| f"**PR description:**\n{pr_body}\n\n" | ||
| f"**Diff (may be truncated):**\n```diff\n{diff}\n```\n\n" | ||
| "Please provide 3–5 bullet points of review feedback." | ||
| ) |
There was a problem hiding this comment.
The generated Markdown wraps the PR diff in a fenced code block, but neither the PR body nor the diff are escaped for occurrences of triple backticks. If either contains ``` the resulting PR comment can render incorrectly. Consider escaping/backtick-neutralizing fence sequences before embedding.
| - `README.md` — Overview, abstract, and evidence index | ||
| - `code/` — Python 3 demonstration scripts (no external dependencies except `matplotlib` for `lorenz.py`) | ||
| - `evidence/` — Evidence index with references |
There was a problem hiding this comment.
This claims the code/ scripts have no external dependencies except matplotlib for lorenz.py, but code/hue_man.py imports numpy and scipy. Update the repo instructions so agents don’t assume a dependency-free runtime.
|
|
||
| ## Validation | ||
|
|
||
| There are no automated tests. To validate changes to Python scripts, run them directly and confirm they produce expected output without errors. There are no linting configs or CI pipelines defined in this repository. |
There was a problem hiding this comment.
This says there are “no linting configs or CI pipelines defined”, but this PR adds a GitHub Actions workflow under .github/workflows/. Update this section to avoid contradicting the repo’s actual CI setup.
| There are no automated tests. To validate changes to Python scripts, run them directly and confirm they produce expected output without errors. There are no linting configs or CI pipelines defined in this repository. | |
| There are no automated tests or dedicated linting configuration files. To validate changes to Python scripts, run them directly and confirm they produce expected output without errors. A basic GitHub Actions workflow exists under `.github/workflows/`, but it does not replace manual validation. |
No
.github/configuration existed, leaving PRs without automated review and no Copilot agent guidance for the repo.Changes
.github/copilot-instructions.md— Repository-wide context for Copilot agents: structure, languages, runtime, and validation steps. Reduces redundant exploration on every session..github/workflows/cascade-review.yml— Triggers on non-draft PR open/sync/reopen. Runs the cascade script then posts the combined review as a PR comment usinggh..github/scripts/cascade_review.py— Core routing logic. Fetches the PR diff, fans out to two independent free-tier GitHub Models agents with distinct review personas, and writes a combined Markdown report to/tmp/cascade_review.md.Models used (both free-tier, $0)
openai/gpt-4o-minimeta/meta-llama-3.1-8b-instructBoth are called via
https://models.inference.ai.azure.com/chat/completionsauthenticated with the workflow'sGITHUB_TOKEN— no extra secrets or billing opt-in required.Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.